package com.veltri.JDroid;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import android.telephony.TelephonyManager;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.Dialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class LoginActivity extends Activity {

	// declare object of type LoginActivity
	LoginActivity self;

	// create tag for purpose of logging authentication exceptions
	private final static String TAG = "JDroidLoginActivity";

	// UserAgent value sent with HTTP Request to ensure request is made from
	// android phone
	final static String UserAgent = "JDroidAppAndroid";

	ProgressDialog progressDialog;
	AuthenticatorThread authenticatorThread;

	// declare and initialize variables for article update check to run every 30
	// seconds
	TimerTask scanTask;
	final Handler handler = new Handler();
	Timer t = new Timer();

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);

		// initialize LoginActivity as this LoginActivity for later reference
		self = this;

		// load the main (login) layout
		setContentView(R.layout.main);

		// initialize login button element
		Button loginButton = (Button) findViewById(R.id.login_button);

		// action listener for login button
		loginButton.setOnClickListener(new OnClickListener() {

			public void onClick(View view) {
				// Check for blank input
				// initializes username and password textfields
				EditText usernameEditText = (EditText) findViewById(R.id.txt_username);
				EditText passwordEditText = (EditText) findViewById(R.id.txt_password);

				// gets values typed in username and password textfields
				String sUserName = usernameEditText.getText().toString();
				String sPassword = passwordEditText.getText().toString();

				if (sUserName.equals("") || sPassword.equals("")) {
					Toast.makeText(LoginActivity.this,
							"Please enter both username and password",
							Toast.LENGTH_SHORT).show();
				} else {
					showDialog(0);
				}
			}
		}

		); // end of loginButton.setOnclickListener
	}

	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case 0:
			progressDialog = new ProgressDialog(LoginActivity.this);
			progressDialog.setTitle("Authenticating");
			progressDialog.setMessage("Please wait...");
			return progressDialog;
		default:
			return null;
		}
	}

	@Override
	protected void onPrepareDialog(int id, Dialog dialog) {
		switch (id) {
		case 0:
			progressDialog.setProgress(0);
			authenticatorThread = new AuthenticatorThread(authHandler);
			authenticatorThread.start();
			break;
		}
	}

	// Define the Handler that receives messages from the thread
	final Handler authHandler = new Handler() {
		public void handleMessage(Message msg) {
			dismissDialog(0);

			int errorCode = msg.arg1;
			if (errorCode == 0) {
				// Successful authentication
				Intent myIntent = new Intent(getBaseContext(), MainActivity.class);
				startActivityForResult(myIntent, 0);
				runTimerTask();
			} else {
				// Show error
				String errorMessage = "";
				switch (errorCode) {
				case 1:
					errorMessage = "Invalid Username";
					break;
				case 2:
					errorMessage = "Invalid Password";
					break;
				case 3:
					errorMessage = "Account not authenticated to use mobile client";
					break;
				default:
					errorMessage = "Unknown error occurred";
					break;
				}
				Toast.makeText(LoginActivity.this, errorMessage,
						Toast.LENGTH_SHORT).show();
			}
		}
	};

	private class AuthenticatorThread extends Thread {
		Handler mHandler;

		AuthenticatorThread(Handler h) {
			mHandler = h;
		}

		public void run() {
			int errorCode = 4;
			try {
				// initializes username and password textfields
				EditText usernameEditText = (EditText) findViewById(R.id.txt_username);
				EditText passwordEditText = (EditText) findViewById(R.id.txt_password);

				// gets values typed in username and password textfields
				String sUserName = usernameEditText.getText().toString();
				String sPassword = passwordEditText.getText().toString();

				// check for successful authentication
				try {
					// gets device information to be sent with HTTP Request
					final TelephonyManager tm = (TelephonyManager) getBaseContext()
							.getSystemService(Context.TELEPHONY_SERVICE);
					String deviceID = tm.getDeviceId();
					int phoneType = tm.getPhoneType();
					String deviceSoftwareVersion = tm
							.getDeviceSoftwareVersion();

					errorCode = postData(sUserName, sPassword, deviceID, phoneType, deviceSoftwareVersion);
				} catch (JSONException e) {
					Log.i("JSON Exception", "authentication unsucessful");
					e.printStackTrace();
				}

			} catch (Exception e) {
				Log.e("ERROR", "Thread Interrupted - Authenticator Thread");
			}
			// Send the error code back through the handler
			Message msg = mHandler.obtainMessage();
			msg.arg1 = errorCode;
			mHandler.sendMessage(msg);
		}
	}

	// authenticates using username and password
	public int postData(String username, String password, String deviceID, int phoneType, String deviceSoftwareVersion) throws JSONException {

		// set up HTTP Post Request
		HttpClient httpclient = new DefaultHttpClient();
		HttpPost httppost = new HttpPost("http://m.jdroid.co/authenticate.php");

		try {

			// add name-value pairs to be sent with request
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(5);
			nameValuePairs.add(new BasicNameValuePair("username", username));
			nameValuePairs.add(new BasicNameValuePair("password", password));
			nameValuePairs.add(new BasicNameValuePair("device_id", deviceID));
			nameValuePairs.add(new BasicNameValuePair("device_phone_type", Integer.toString(phoneType)));
			nameValuePairs.add(new BasicNameValuePair("device_software_version", deviceSoftwareVersion));
			httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

			// add header to ensure request is made from android device
			httppost.addHeader("User-Agent", UserAgent);

			// Execute HTTP Request and get the response
			HttpResponse response = httpclient.execute(httppost);

			// get response code of HTTP Request (successful or not)
			int responseCode = response.getStatusLine().getStatusCode();

			// get the raw JSON response
			String responseText = "";
			HttpEntity httpEntity = response.getEntity();
			InputStream in = httpEntity.getContent();
			BufferedReader reader = new BufferedReader( new InputStreamReader(in));
			StringBuilder str = new StringBuilder();
			String line = null;
			while ((line = reader.readLine()) != null) {
				str.append(line + "\n");
			}
			in.close();
			responseText = str.toString();

			HttpEntity resEntityGet = httpEntity;
			String rawResponse = "";
			if (resEntityGet != null) {
				rawResponse = responseText;
			}

			// log success or failure of authentication
			if (responseCode == HttpStatus.SC_OK) {
				Log.i(TAG, "Successful authentication");

				// decode JSON response and get session ID
				JSONObject jObject = new JSONObject(rawResponse);
				((MyApplication) this.getApplication()).setSessionId(jObject
						.getString("session_id"));

				return 0;
			} else {
				if (responseCode == HttpStatus.SC_FORBIDDEN) {
					if (responseText.length() > 0) {

						try {
							JSONObject responseJSON = new JSONObject(
									responseText);
							
							// get error
							int errorCode = responseJSON.getInt("error");
							return errorCode;

						} catch (Exception e) {
							Log.e(TAG, "JSON exception " + e.toString());

						}
					}

					Log.e(TAG, "Error authenticating w/403 - " + responseText);
					return 4;
				}
				Log.e(TAG,
						"Error authenticating - HTTP Code other than 403 received "
								+ response.getStatusLine() + " "
								+ response.getEntity().toString());
			}
		} catch (final IOException e) {
			Log.e("AUTHENTICATION", "IOException", e);
		}
		return 4;
	}

	private class CheckNewArticleTask extends
			AsyncTask<Integer, Void, ArrayList<Integer>> {

		@Override
		protected ArrayList<Integer> doInBackground(Integer... params) {
			ArrayList<Integer> result = new ArrayList<Integer>();

			int index = (Integer) params[0];

			// set up HTTP Post
			HttpClient httpclient = new DefaultHttpClient();
			HttpPost httppost = new HttpPost(
					"http://m.jdroid.co/new_articles.php");

			// get device ID
			final TelephonyManager tm = (TelephonyManager) getBaseContext()
					.getSystemService(Context.TELEPHONY_SERVICE);
			String deviceID = tm.getDeviceId();

			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(4);
			try {

				// create name-value pairs to be sent with HTTP Request
				nameValuePairs.add(new BasicNameValuePair("device_id", deviceID));
				String sessionId = ((MyApplication) self.getApplication()).getSessionId();
				nameValuePairs.add(new BasicNameValuePair("session_id", sessionId));
				((MyApplication) self.getApplication()).setCategories();
				int myCategory = ((MyApplication) self.getApplication()).getCategory(index);
				nameValuePairs.add(new BasicNameValuePair("category_id", Integer.toString(myCategory)));
				// nameValuePairs.add(new BasicNameValuePair("category_id",
				// "19"));
				int timestamp = ((MyApplication) self.getApplication()).getTimestamp(index);
				nameValuePairs.add(new BasicNameValuePair("time", Integer.toString(timestamp)));
				httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

				// add header that ensures HTTP Request is being made from
				// Android device
				httppost.addHeader("User-Agent", LoginActivity.UserAgent);

				// execute HTTP Request
				HttpResponse response = httpclient.execute(httppost);
				HttpEntity resEntityGet = response.getEntity();

				// get raw JSON response
				String rawResponse = "";
				if (resEntityGet != null) {
					rawResponse = EntityUtils.toString(resEntityGet);
				}

				// decode JSON response
				// gets ArrayList of articles titles
				// gets hash table of article title and id (key and value)
				JSONObject wholeResponse = new JSONObject(rawResponse);
				int numArticles = wholeResponse.getInt("num_articles");
				int currentTime = wholeResponse.getInt("current_time");
				int fromTime = wholeResponse.getInt("from_time");
				
				result.add(index);
				result.add(numArticles);
				result.add(currentTime);
				result.add(fromTime);
				return result;

			} catch (Exception e) {
				Log.e("JSON Parse", "response parsing failed - check new article task");
			}
			return null;
		}

		@Override
		protected void onPostExecute(ArrayList<Integer> response) {
			if (response != null) {
				int index = response.get(0);
				int numArticles = response.get(1);

				if (numArticles > 0) {
					// Reset time stamp
					int timestamp = response.get(2);
					((MyApplication) self.getApplication()).setTimestamp( index, timestamp);
					
					// create notification
					String ns = Context.NOTIFICATION_SERVICE;
					NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);

					// set image of notification
					int icon = R.drawable.ic_imagetab_selected;
					switch( index) {
					case 0:
						icon = R.drawable.ic_tab_artists_grey;
						break;
					case 1:
						icon = R.drawable.ic_movietab_selected;
						break;
					case 2:
						icon = R.drawable.ic_imagetab_selected;
						break;
					}
					CharSequence tickerText = "New JDroid Articles";

					// initialize notification using current time as
					// parameter
					long when = System.currentTimeMillis();
					Notification notification = new Notification(icon,
							tickerText, when);
					notification.flags |= Notification.FLAG_AUTO_CANCEL;

					// get application context
					Context context = getApplicationContext();

					((MyApplication) self.getApplication()).setCategoryNames();

					// set text for notification
					String s = (numArticles == 1) ? "" : "s";
					String categoryName = ((MyApplication) self
							.getApplication()).getCategoryName(index);
					CharSequence contentTitle = "JDroid";
					CharSequence contentText = "New Article" + s + " in " + categoryName;
					Intent notificationIntent = new Intent(self,
							MainActivity.class);
					notificationIntent.putExtra("TAB_INDEX", index);

					// create intent on which notification runs on
					PendingIntent contentIntent = PendingIntent.getActivity(
							self, 0, notificationIntent, 0);
					notification.setLatestEventInfo(context, contentTitle,
							contentText, contentIntent);

					// notifies that notification processed successfully
					final int NOTIFICATION_ID = 1;
					mNotificationManager.notify( NOTIFICATION_ID, notification);
				}
			}
		}
	}

	public void runTimerTask() {

		scanTask = new TimerTask() {
			public void run() {
				handler.post(new Runnable() {
					public void run() {
						// Check if there are new articles in the three categories

						new CheckNewArticleTask().execute( 0);
						new CheckNewArticleTask().execute( 1);
						new CheckNewArticleTask().execute( 2);

					}
				});
			}
		};

		// schedule scanTask to run every 30 seconds after 30 seconds of initial
		// delay
		t.schedule(scanTask, 30000, 30000);

	}

}